#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <chrono>

uint16_t crc16_mcrf4xx(uint16_t crc, uint8_t *data, size_t len)
{
    if (!data || len < 0)
        return crc;

    while (len--)
    {
        crc ^= *data++;
        for (int i = 0; i < 8; i++)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8408;
            else
                crc = (crc >> 1);
        }
        // uint8_t tmp = *data++ ^ (crc & 0xFF);
        // tmp ^= tmp << 4;
        // crc = (crc >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4);
    }
    return crc;
}

uint16_t crc16_mcrf4xx2(uint16_t crc, uint8_t *data, size_t len)
{
    if (!data || len < 0)
        return crc;

    while (len--)
    {
        uint8_t tmp = *data++ ^ (crc & 0xFF);
        tmp ^= tmp << 4;
        crc = (crc >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4);
    }
    return crc;
}

uint16_t crc16_mcrf4xx3(uint8_t *data, size_t len)
{
    uint16_t crc = 0xFFFF;
    if (!data || len < 0)
        return crc;

    while (len--)
    {
        uint8_t tmp = *data++ ^ (crc & 0xFF);
        tmp ^= tmp << 4;
        crc = (crc >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4);
    }
    return crc;
}

uint16_t crc16_mcrf4xx4(uint8_t *data, size_t len)
{
    uint16_t crc = 0xFFFF;
    if (!data || len < 0)
        return crc;

    while (len--)
    {
        crc ^= *data++;
        for (int i = 0; i < 8; i++)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8408;
            else
                crc = (crc >> 1);
        }
    }
    return crc;
}

int main(int argc, char **argv)
{
    unsigned char szT[4096];
    for (int i = 0; i < 4096; i++)
    {
        szT[i] = i;
    }

    {
        uint16_t crc = 0;
        auto ts = std::chrono::system_clock::now();
        for (int j = 0; j < 10000; j++)
        {
            szT[0] = j;
            crc += crc16_mcrf4xx3(szT, 4096);
        }
        auto te = std::chrono::system_clock::now();
        std::cout << (double)(te - ts).count() / 1000000 << " ms\t" << (te - ts).count() << " count\t" << crc << std::endl;
    }
    {
        uint16_t crc = 0;
        auto ts = std::chrono::system_clock::now();
        for (int j = 0; j < 10000; j++)
        {
            szT[0] = j;
            crc += crc16_mcrf4xx4(szT, 4096);
        }
        auto te = std::chrono::system_clock::now();
        std::cout << (double)(te - ts).count() / 1000000 << " ms\t" << (te - ts).count() << " count\t" << crc << std::endl;
    }
    return 0;
}

// Windows10 vs2022编译
// 算法一：Debug > RelWithDebInfo > MinSizeRel > Release
// 算法二：RelWithDebInfo > Debug > MinSizeRel > Release
// D:\Crc\crc16_mcrf4xx\build>Debug\crc16_mcrf4xx.exe
// 1.61927 ms      1619266 count   57336
// 18.3762 ms      18376234 count  57336
// 
// D:\Crc\crc16_mcrf4xx\build>Debug\crc16_mcrf4xx.exe
// 1.59116 ms      1591155 count   57336
// 18.1764 ms      18176390 count  57336
// 
// D:\Crc\crc16_mcrf4xx\build>Debug\crc16_mcrf4xx.exe
// 1.50169 ms      1501693 count   57336
// 18.0803 ms      18080342 count  57336
// 
// D:\Crc\crc16_mcrf4xx\build>Release\crc16_mcrf4xx.exe
// 1.13976 ms      1139756 count   57336
// 4.51074 ms      4510736 count   57336
// 
// D:\Crc\crc16_mcrf4xx\build>Release\crc16_mcrf4xx.exe
// 1.20364 ms      1203636 count   57336
// 4.41631 ms      4416307 count   57336
// 
// D:\Crc\crc16_mcrf4xx\build>Release\crc16_mcrf4xx.exe
// 1.2198 ms       1219800 count   57336
// 4.57671 ms      4576709 count   57336
// 
// D:\Crc\crc16_mcrf4xx\build>MinSizeRel\crc16_mcrf4xx.exe
// 1.24319 ms      1243189 count   57336
// 5.23646 ms      5236457 count   57336
// 
// D:\Crc\crc16_mcrf4xx\build>MinSizeRel\crc16_mcrf4xx.exe
// 1.21288 ms      1212885 count   57336
// 5.25693 ms      5256931 count   57336
// 
// D:\Crc\crc16_mcrf4xx\build>MinSizeRel\crc16_mcrf4xx.exe
// 1.26087 ms      1260874 count   57336
// 5.22018 ms      5220179 count   57336
// 
// D:\Crc\crc16_mcrf4xx\build>RelWithDebInfo\crc16_mcrf4xx.exe
// 1.55119 ms      1551188 count   57336
// 20.7624 ms      20762371 count  57336
// 
// D:\Crc\crc16_mcrf4xx\build>RelWithDebInfo\crc16_mcrf4xx.exe
// 1.47052 ms      1470515 count   57336
// 20.9393 ms      20939259 count  57336
// 
// D:\Crc\crc16_mcrf4xx\build>RelWithDebInfo\crc16_mcrf4xx.exe
// 1.53974 ms      1539737 count   57336
// 20.8057 ms      20805726 count  57336
// 
//
// Ubuntu20.04.6 gcc编译
// 算法一：Debug > RelWithDebInfo > MinSizeRel > Release
// 算法二：Debug > MinSizeRel > Release > RelWithDebInfo
// Debug:
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 161.021 ms      161020670 count 57336
// 2125.01 ms      2125007948 count        57336
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 166.122 ms      166121583 count 57336
// 2128.49 ms      2128485658 count        57336
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 181.816 ms      181816454 count 57336
// 2119.3 ms       2119302940 count        57336
// 
// 
// Release:
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 118.852 ms      118852118 count 57336
// 1042.85 ms      1042849012 count        57336
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 118.253 ms      118253089 count 57336
// 1052.47 ms      1052466950 count        57336
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 117.445 ms      117445189 count 57336
// 1043.81 ms      1043805348 count        57336
// 
// 
// MinSizeRel:
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 121.117 ms      121116564 count 57336
// 1396.25 ms      1396249757 count        57336
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 119.168 ms      119168053 count 57336
// 1402.08 ms      1402077151 count        57336
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 121.957 ms      121957241 count 57336
// 1400.49 ms      1400486482 count        57336
// 
// 
// RelWithDebInfo:
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 128.951 ms      128950875 count 57336
// 569.23 ms       569229667 count 57336
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 134.316 ms      134315643 count 57336
// 571.967 ms      571967407 count 57336
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 130.463 ms      130463228 count 57336
// 568.878 ms      568877832 count 57336
// 
//
//

//     {
//         uint16_t crc = 0;
//         auto ts = std::chrono::system_clock::now();
//         for (int j = 0; j < 10000; j++)
//         {
//             crc += crc16_mcrf4xx3(szT, 4096);
//         }
//         auto te = std::chrono::system_clock::now();
//         std::cout << (double)(te - ts).count() / 1000000 << " ms\t" << (te - ts).count() << " count\t" << crc << std::endl;
//     }
//     {
//         uint16_t crc = 0;
//         auto ts = std::chrono::system_clock::now();
//         for (int j = 0; j < 10000; j++)
//         {
//             crc += crc16_mcrf4xx4(szT, 4096);
//         }
//         auto te = std::chrono::system_clock::now();
//         std::cout << (double)(te - ts).count() / 1000000 << " ms\t" << (te - ts).count() << " count\t" << crc << std::endl;
//     }
// 
// Debug:
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 166.528 ms      166527865 count 41728
// 1873.93 ms      1873930337 count        41728
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 186.534 ms      186534437 count 41728
// 1893.46 ms      1893461044 count        41728
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 157.063 ms      157063408 count 41728
// 1896.94 ms      1896943595 count        41728
// 
// Release:
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 116.704 ms      116703762 count 41728
// 708.146 ms      708145831 count 41728
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 118.429 ms      118429027 count 41728
// 703.165 ms      703165179 count 41728
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 119.653 ms      119652579 count 41728
// 694.369 ms      694368937 count 41728
// 
// MinSizeRel:
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 0.012777 ms     12777 count     41728
// 0.1782 ms       178200 count    41728
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 0.012041 ms     12041 count     41728
// 0.159214 ms     159214 count    41728
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 0.012045 ms     12045 count     41728
// 0.16203 ms      162030 count    41728
// 
// RelWithDebInfo:
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 0.013184 ms     13184 count     41728
// 0.058525 ms     58525 count     41728
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 0.013731 ms     13731 count     41728
// 0.068147 ms     68147 count     41728
// xtwh@u2004:~/progs/Crc/crc16_mcrf4xx/build$ /home/xtwh/progs/Crc/crc16_mcrf4xx/build/crc16_mcrf4xx
// 0.013179 ms     13179 count     41728
// 0.060357 ms     60357 count     41728
// 
// 

//    {
//        auto ts = std::chrono::system_clock::now();
//        for (int j = 0; j < 10000; j++)
//        {
//            uint16_t crc = crc16_mcrf4xx3(szT, 4096);
//        }
//        auto te = std::chrono::system_clock::now();
//        std::cout << (double)(te - ts).count() / 1000000 << "ms\t" << (te - ts).count() << " count" << std::endl;
//    }
//    {
//        auto ts = std::chrono::system_clock::now();
//        for (int j = 0; j < 10000; j++)
//        {
//            uint16_t crc = crc16_mcrf4xx4(szT, 4096);
//        }
//        auto te = std::chrono::system_clock::now();
//        std::cout << (double)(te - ts).count() / 1000000 << "ms\t" << (te - ts).count() << " count" << std::endl;
//    }
//
// Debug:
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 204.448ms       204448179 count
// 2097.76ms       2097759675 count
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 173.448ms       173448035 count
// 2069.91ms       2069907547 count
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 202.048ms       202048472 count
// 2051.06ms       2051057597 count
//
// Release:
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 0.000128ms      128 count
// 4.3e-05ms       43 count
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 0.000107ms      107 count
// 4.6e-05ms       46 count
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 0.000844ms      844 count
// 7.3e-05ms       73 count
//
// MinSizeRel:
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 0.000134ms      134 count
// 6.1e-05ms       61 count
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 0.000111ms      111 count
// 4.6e-05ms       46 count
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 0.000127ms      127 count
// 3.7e-05ms       37 count
//
// RelWithDebInfo:
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 8.8e-05ms       88 count
// 3.8e-05ms       38 count
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 0.00012ms       120 count
// 4.9e-05ms       49 count
// xtwh@u2004:~/progs/TestCrc/build$ /home/xtwh/progs/TestCrc/build/TestCrc
// 0.000172ms      172 count
// 4.6e-05ms       46 count
